package com.openarena.statistics;

import com.openarena.logic.utils.FacesUtil;
import com.openarena.model.dao.GameDAO;
import com.openarena.model.dao.PlayerDAO;
import com.openarena.model.Game;
import com.openarena.model.GameComment;
import com.openarena.model.Player;
import com.openarena.model.dao.GameCommentDAO;
import com.openarena.other.suggestions.Suggestion;
import java.io.IOException;
import java.io.Serializable;
import java.text.ParseException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import org.primefaces.model.chart.CartesianChartModel;
import org.primefaces.model.chart.ChartSeries;

@ManagedBean
@SessionScoped
public class Statistics implements Serializable {

    private static final Logger logger = Logger.getLogger(Statistics.class.getCanonicalName());
    private static final List<GamePeriod> gamePeriods = new ArrayList<GamePeriod>();

    private List<PlayerSummaryStat> returnedGeneralStatistics;
    private List<Player> allPlayers;
    private List<Game> games;
    private List<PlayerSummaryStat> allGeneralStatistics;
    private Map<Player, ChartSeries> chartEffectivenessMap;
    private Map<Player, ChartSeries> chartDKRatioMap;
    private String gamePeriod;
    private List<String> selectedPlayersIds;

    static {
        Calendar c;

        c = Calendar.getInstance();
        c.add(Calendar.DATE, -30);
        gamePeriods.add(new GamePeriod("30 dias", c.getTime()));

        c = Calendar.getInstance();
        c.add(Calendar.DATE, -90);
        gamePeriods.add(new GamePeriod("90 dias", c.getTime()));

        c = Calendar.getInstance();
        c.add(Calendar.MONTH, -6);
        gamePeriods.add(new GamePeriod("6 meses", c.getTime()));

        c = Calendar.getInstance();
        c.add(Calendar.YEAR, -1);
        gamePeriods.add(new GamePeriod("1 año", c.getTime()));

        c = Calendar.getInstance();
        c.set(2010, 0, 1);
        gamePeriods.add(new GamePeriod("Desde el inicio", c.getTime()));
    }

    public Statistics() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DATE, -90);
        PlayerDAO playerDAO = new PlayerDAO();
        allPlayers = playerDAO.getAllPlayers();
        selectedPlayersIds = new ArrayList<String>();
        for (Player player : playerDAO.getActivePlayers()) {
            selectedPlayersIds.add(String.valueOf(player.getId()));
        }

        gamePeriod = new GamePeriod("", c.getTime()).getValue();
        allGeneralStatistics = new ArrayList<PlayerSummaryStat>();
        returnedGeneralStatistics = new ArrayList<PlayerSummaryStat>();
        chartEffectivenessMap = new HashMap<Player, ChartSeries>();
        chartDKRatioMap = new HashMap<Player, ChartSeries>();

        games = new GameDAO().getGamesSinceDate(c.getTime());

        logger.log(Level.INFO, "Started Statistics Bean");

        init();
    }

    public List<PlayerSummaryStat> getGeneralStatistics() {
        return returnedGeneralStatistics;
    }

    public CartesianChartModel getChartEffectiveness() {
        CartesianChartModel chartEffectiveness = new CartesianChartModel();

        for (Map.Entry<Player, ChartSeries> entry : chartEffectivenessMap.entrySet()) {
            if (selectedPlayersIds.contains(entry.getKey().getId().toString())) {
                ChartSeries chartSeries = entry.getValue();
                chartSeries.setLabel(entry.getKey().getName());
                chartEffectiveness.addSeries(chartSeries);
            }
        }

        return chartEffectiveness;
    }

    public CartesianChartModel getChartDKRatio() {
        CartesianChartModel chartDKRatio = new CartesianChartModel();

        for (Map.Entry<Player, ChartSeries> entry : chartDKRatioMap.entrySet()) {
            if (selectedPlayersIds.contains(entry.getKey().getId().toString())) {
                ChartSeries chartSeries = entry.getValue();
                chartSeries.setLabel(entry.getKey().getName());
                chartDKRatio.addSeries(chartSeries);
            }
        }

        return chartDKRatio;
    }

    private void init() {
        long time = System.currentTimeMillis();

        logger.log(Level.INFO, "Games {0}. SelectedPlayers {1}", new Object[]{games.size(), selectedPlayersIds.size()});

        allGeneralStatistics.clear();
        chartEffectivenessMap.clear();
        chartDKRatioMap.clear();

        for (Player player : allPlayers) {
            allGeneralStatistics.add(new PlayerSummaryStat(player));
            chartEffectivenessMap.put(player, new ChartSeries());
            chartDKRatioMap.put(player, new ChartSeries());
        }

        for (int i = 0; i < games.size(); i++) {
            Game game = games.get(i);

            for (PlayerSummaryStat stat : allGeneralStatistics) {
                Player player = stat.getPlayer();
                if (game.played(player)) {
                    stat.addMatchPlayed();
                    stat.addPlayedSeconds(game.getDuration());
                    stat.addPoints(game.points(player));
                    stat.addKills(game.kills(player));
                    stat.addDeaths(game.deaths(player));

                    if (game.won(player)) {
                        stat.addMatchWon();
                    }
                    if (game.mvp(player)) {
                        stat.addTimeMVP();
                    }
                }

                chartDKRatioMap.get(player).set(String.valueOf(i + 1), stat.getKdRatio());
                chartEffectivenessMap.get(player).set(String.valueOf(i + 1), 100 * stat.getEffectiveness());
            }
        }

        changeSelectedPlayers();
        logger.log(Level.INFO, "Procesado en {0}", (System.currentTimeMillis() - time) / 1000);
    }

    public void setSelectedGamePeriod(String selectedGamePeriod) {
        gamePeriod = selectedGamePeriod;
    }

    public String getSelectedGamePeriod() {
        return gamePeriod;
    }

    public void changeSelectedPlayers() {
        returnedGeneralStatistics.clear();

        for (PlayerSummaryStat stat: allGeneralStatistics) {
            if (selectedPlayersIds.contains(String.valueOf(stat.getPlayer().getId()))) {
                returnedGeneralStatistics.add(stat);
            }
        }
    }

    public void changeGamePeriod() {

        Date date = new Date();
        try {
            logger.log(Level.INFO, "Partidos desde {0}", gamePeriod);
            date = GamePeriod.getGamePeriodFormatter().parse(gamePeriod);
        } catch (ParseException ex) {
            logger.log(Level.SEVERE, null, ex);
        }

        games = new GameDAO().getGamesSinceDate(date);

        init();
    }

    public List<GamePeriod> getGamePeriods() {
        return gamePeriods;
    }

    public List<Player> getAllPlayers() {
        return allPlayers;
    }

    public List<String> getSelectedPlayersIds() {
        return selectedPlayersIds;
    }

    public void setSelectedPlayersIds(List<String> selectedPlayersIds) {
        this.selectedPlayersIds = selectedPlayersIds;
    }
}
